#! /usr/bin/env python

import os
import time
import threading
import re
from utils import singleton

class Dumper():
    """ Dump ring data for scheduler. """
    version = 0.1

    def __init__(self, args):
        self.path = args[0]
    def dump(self):
        pass
    
# Dump load of VMs
@singleton
class LoadDumper(Dumper):
    def __init__(self, args):
        Dumper.__init__(self, args)
        self.loads = open(self.path, 'r')

    def __del__(self):
        self.loads.close()
        
    def dump(self):
        result = {} # domid:load

        # read named pipe
        lines = self.loads.read(4096)
        lines = lines.splitlines()
        for i in range(len(lines)-1): # last line is empty line
            words = lines[i].split()
            result[int(words[0])] = float(words[1])
        return result

# Dump ring infomation
@singleton
class RingDumper(Dumper, threading.Thread):
    def __init__(self, args):
        Dumper.__init__(self, args)
        threading.Thread.__init__(self)
        self.rings = {}
        self.lock = threading.Lock()
        self.factor = int(args[1])

    def run(self):
        # Save result
        overflows = {} # times of overflow ring queue of dom
        overlongs = {} # times of overlong ring queue of dom

        # read /proc/ring/
        while True:
            # Get fresh file list
            fnames = os.listdir(self.path)
            tmp = {}
            overflows.clear()
            overlongs.clear()
            for fname in fnames:
                tmp[int(fname)] = 0
                overflows[int(fname)] = 0
                overlongs[int(fname)] = 0
                
            # Inspect ring buffer of domains
            # It's frequence is larger than load inspect frequence
            for i in range(100):
                for fname in fnames:
                    domain = open(self.path + '/'+ str(fname))
                    line = domain.next()
                    #pattern = r'\w+:\s+(\d+),\s+\w+:\s+(\d+),\s+\w+:\s+(\d+),\s+\w+:\s+(\d+),\s+\w+:\s+(\d+)'
                    mtchs = re.search(r'\w+:\s+(\d+),\s+\w+:\s+(\d+),\s+\w+:\s+(\d+),\s+\w+:\s+(\d+),\s+\w+:\s+(\d+)', line)
                    overflows[int(mtchs.group(1))] += int(mtchs.group(2))
                    if int(mtchs.group(3)) >= 128:
                        overlongs[int(mtchs.group(1))] += 1
                time.sleep(0.0009 + (self.factor-1)*0.001)
            # Compute sensitive domains
            for fname in fnames:
                if overflows[int(fname)] >= 6:
                    tmp[int(fname)] = 1
                if overlongs[int(fname)] >= 24:
                    tmp[int(fname)] = 1
            self.lock.acquire()
            self.rings = tmp
            self.lock.release()

    def dump(self):
        self.lock.acquire()
        rns = self.rings
        self.lock.release()
        return rns

# Dump Bps, pps, bps
@singleton
class NetworkDumper(Dumper):
    def __init__(self, args):
        Dumper.__init__(self, args)
        self.netstats = open(self.path, 'r')

    def __del__(self):
        self.netstats.close()

    def dump(self):
        result = {} # domid:[rx_bytes, tx_bytes, rx_packets, tx_packets]

        # read named pipe
        lines = self.netstats.read(4096)
        lines = lines.splitlines()
        for i in range(len(lines)-1): # [0,len-1]
            words = lines[i].split()
            statistics = [0, 0, 0, 0]
            statistics[0] = long(words[1])
            statistics[1] = long(words[2])
            statistics[2] = long(words[3])
            statistics[3] = long(words[4])
            result[int(words[0])] = statistics
        return result
